package br.ufrgs.ga.model;

import br.ufrgs.ga.operators.CrossoverOperator;
import br.ufrgs.ga.operators.ICrossover;
import br.ufrgs.ga.operators.IMutation;
import br.ufrgs.ga.operators.MutationOperator;

public class TSPChromosome extends AbstractChromosome<String> {

	private final ICrossover<String> crossoverOperator;
	private final IMutation<String> mutationOperator;
	
	protected TSPChromosome(String dnaStrand) {
		super(dnaStrand);
		this.crossoverOperator = new CrossoverOperator();
		this.mutationOperator = new MutationOperator();
	}
	
	protected TSPChromosome(String dnaStrand, ICrossover<String> crossoverOperator) {
		super(dnaStrand);
		this.crossoverOperator = crossoverOperator;
		this.mutationOperator = new MutationOperator();
	}
	
	protected TSPChromosome(String dnaStrand, IMutation<String> mutationOperator) {
		super(dnaStrand);
		this.crossoverOperator = new CrossoverOperator();
		this.mutationOperator = mutationOperator;
	}
	
	protected TSPChromosome(String dnaStrand, ICrossover<String> crossoverOperator, IMutation<String> mutationOperator) {
		super(dnaStrand);
		this.crossoverOperator = crossoverOperator;
		this.mutationOperator = mutationOperator;
	}
	
	@Override
	public boolean isValid(String dnaStrand) {
		try {
			if (dnaStrand == null || dnaStrand.isEmpty())
				return false;
			
			int maxCityId = Integer.MIN_VALUE;
			for(int i = 0; i < dnaStrand.length(); i++) {
				int cityId = Integer.parseInt(dnaStrand.subSequence(i, i+1).toString());
				if (cityId > maxCityId)
					maxCityId = cityId;
			}
			if (maxCityId >= dnaStrand.length())
				return false;
			
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	@Override
	public void mutate() {
		this.dnaStrand = mutationOperator.execute(dnaStrand);
	}

	@Override
	public IChromosome<String> reproduce(IChromosome<String> chromosome) {
		return new TSPChromosome(crossoverOperator.execute(dnaStrand, chromosome.getDnaStrand()), crossoverOperator, mutationOperator);
	}
	
	@Override
	public IChromosome<String> clone() throws CloneNotSupportedException {
		return new TSPChromosome(this.dnaStrand, this.crossoverOperator, this.mutationOperator);
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		
		if (this == obj) {
			return true;
			
		} else if (obj instanceof TSPChromosome) {
			IChromosome<String> chromosome = (TSPChromosome)obj;
			
			if (this.getDnaStrand().equals(chromosome.getDnaStrand())) {
				return true;
			}
			
			return false;
			
		} else {
			return false;
		}
	}
}
